#include <unistd.h>
#include <string.h>

#include "Sunnet.h"
#include "LuaAPI.h"

int LuaAPI::NewService(lua_State *L) {
    int num = lua_gettop(L);
    if (lua_isstring(L, -1) == 0) { // succ -> 1
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    size_t len = 0;
    const char *str = lua_tolstring(L, -1, &len); 
    // Lua虚拟机gc机制，会判断释放。
    // 为避免冲突，复制一份，在c层管理（shared_ptr）
    char *typeStr = new char[len + 1];
    typeStr[len] = '\0';
    memcpy(typeStr, str, len);

    auto type = make_shared<string>(typeStr);
    uint32_t id = Sunnet::instance->NewService(type);
    lua_pushinteger(L, id);
    return 1;
}

int LuaAPI::KillService(lua_State *L) {
    int num = lua_gettop(L);
    if (lua_isinteger(L, -1) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    int id = lua_tointeger(L, -1);
    Sunnet::instance->KillService(id);
    lua_pushboolean(L, true);
    return 1;
}

// sunnet.Send(source, address, msg)
int LuaAPI::Send(lua_State *L) {
    int num = lua_gettop(L);
    if (num != 3) {
        lua_pushnil(L);
        lua_pushstring(L, "Incorrect number of arguments. Expected 3.");
        return 2;
    }
    if (lua_isinteger(L, -3) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    int source = lua_tointeger(L, -3);
    if (lua_isinteger(L, -2) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    int address = lua_tointeger(L, -2);
    if (lua_isstring(L, -1) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    size_t len;
    const char *str = lua_tolstring(L, -1, &len);
    char *msgStr = new char[len + 1];
    msgStr[len] = '\0';
    memcpy(msgStr, str, len);

    auto msg = make_shared<ServiceMsg>();
    msg->type = BaseMsg::TYPE::SERVICE;
    msg->source = source;
    msg->buff = shared_ptr<char>(msgStr);
    msg->size = len;
    Sunnet::instance->Send(address, msg);

    lua_pushboolean(L, true);
    return 1;
}

int LuaAPI::Listen(lua_State *L) {
    int num = lua_gettop(L);
    if(lua_isinteger(L, -2) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    int port = lua_tointeger(L, 1);
    if(lua_isinteger(L, -1) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    int id = lua_tointeger(L, 2);
    int fd = Sunnet::instance->Listen(port, id);
    lua_pushinteger(L, fd);
    return 1;
}

int LuaAPI::CloseConn(lua_State *L) {
    int num = lua_gettop(L);
    if(lua_isinteger(L, -1) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    int fd = lua_tointeger(L, -1);
    Sunnet::instance->CloseConn(fd);
    lua_pushboolean(L, true);
    return 1;
}

int LuaAPI::Write(lua_State *L) {
    int num = lua_gettop(L);
    if (lua_isinteger(L, -2) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    int address = lua_tointeger(L, -2);
    if (lua_isstring(L, -1) == 0) {
        lua_pushnil(L);
        lua_pushstring(L, strerror(errno));
        return 2;
    }
    size_t len;
    const char *str = lua_tolstring(L, -1, &len);
    
    int byte = write(address, str, len);
    lua_pushinteger(L, byte);
    return 1;   
}

void LuaAPI::Register(lua_State *L) {
    static const luaL_Reg l[] = {
        { "NewService", NewService },
        { "KillService", KillService },
        { "Send", Send }, 
        { "Listen", Listen },
        { "CloseConn", CloseConn },
        { "Write", Write },
        { NULL, NULL },
    };
    luaL_newlib(L, l); // 栈中创建新表，数组l函数注册到表中
    lua_setglobal(L, "sunnet"); // 栈顶元素放入全局空间，并重新命名
    return ;
}